package com.zbb.comm.controller;


import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.zbb.comm.feignclient.UserServiceClient;
import com.zbb.comm.po.*;
import com.zbb.comm.service.AssociationUserService;
import com.zbb.comm.service.CroupChatContactsService;
import com.zbb.comm.service.MessageService;
import com.zbb.base.util.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint(value = "/chat/{userId}")
public class WebSocketServer {


    static UserServiceClient userServiceClient;

    static RedisUtil redisUtil;

    @Autowired
    @Qualifier("redisUtil")
    public void setRedisTemplate(RedisUtil redisUtil){
        this.redisUtil = redisUtil;
    }

    static AssociationUserService associationUserService;

    static CroupChatContactsService croupChatContactsService;

    static MessageService messageService;
    @Autowired
    public void setLabRemoteService(UserServiceClient userServiceClient, AssociationUserService associationUserService, CroupChatContactsService croupChatContactsService, MessageService messageService) {
        WebSocketServer.userServiceClient = userServiceClient;
        WebSocketServer.associationUserService = associationUserService;
        WebSocketServer.croupChatContactsService = croupChatContactsService;
        WebSocketServer.messageService = messageService;
    }


    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    /**
     * 记录当前在线用户
     */
    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();

    /**
     * 存储当前用户信息
     * @param session
     * @param userId
     */
    public static final Map<String, User> userMap = new ConcurrentHashMap<>();

    //连接成功
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        /**
         * 1.连接成功，查询数据库中联系对象，获取其他好友在线状态。
         * 2.向在线好友推送自己上线，更新状态消息。
         *
         */
        Map<String, User> associationMap = new ConcurrentHashMap<>();
        User user = userServiceClient.querytUser(userId);
        sessionMap.put(userId, session);
        userMap.put(userId, user);
        associationMap.put(userId, user);
        log.info("有新用户加入，userId={}, 当前在线人数为：{}", userId, sessionMap.size());
        List<AssociationUser> associationUsers= associationUserService.selectAssociationUser(userId);
        //群聊联系人
        List<CroupChatContactVo> croupChatContactVos = croupChatContactsService.selectCroupById(userId);
        JSONObject croupResult = new JSONObject();
        croupResult.set("croupUsers",croupChatContactVos);
        this.sendMessage(JSON.toJSONString(croupResult), session);
        //遍历订单列表
        for (AssociationUser associationUser:associationUsers) {
            //查询出所有用户信息。
            User user1 = userServiceClient.querytUser(associationUser.getAssociatedUserId());
            user1.setNoReadNum(0);
//            判断用户是否在线
            if (sessionMap.containsKey(associationUser.getAssociatedUserId())){
                user1.setLoginState(true);
                JSONObject result = new JSONObject();
                JSONObject jsonObject = new JSONObject();
                jsonObject.set("userId", userId);
                result.set("loginTo", jsonObject);
                //如过对方在线推送自己上线消息
                Session toSession = sessionMap.get(associationUser.getAssociatedUserId());
                this.sendMessage(JSON.toJSONString(result), toSession);
            }
            associationMap.put(associationUser.getAssociatedUserId(),user1);
        }
        JSONObject result = new JSONObject();
        JSONArray array = new JSONArray();
        result.set("users", array);
        for (Object key : associationMap.keySet()) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.set("userId", key);
            jsonObject.set("userInfo", associationMap.get(key));
            array.add(jsonObject);
        }
        this.sendMessage(JSON.toJSONString(result), session);
        //获取离线信息
        List<Message> messages = messageService.selectMessageList(userId);
        for (Message message:messages) {
            CommMessage message1 = new CommMessage();
            message1.setToUserId(message.getReceivUserId());
            message1.setMessage(message.getMessage());
            message1.setFromUser(userServiceClient.querytUser(message.getSendUserId()));
            if (session != null) {
                // 消息组装
                this.sendMessage(JSON.toJSONString(message1), session);
                log.info("发送给用户userId={}，消息：{}", message.getReceivUserId(), JSON.toJSONString(message1));
            }
        }
        //删除离线存储消息
        messageService.deleteMessageList(userId);
//        sendAllMessage(JSONUtil.toJsonStr(result));  // 后台发送消息给所有的客户端
    }


    //关闭连接
    @OnClose
    public void onClose(Session session, @PathParam("userId") String userId) {
        List<AssociationUser> associationUsers= associationUserService.selectAssociationUser(userId);
        for (AssociationUser associationUser:associationUsers) {
//            判断用户是否在线
            if (sessionMap.containsKey(associationUser.getAssociatedUserId())){
                JSONObject result = new JSONObject();
                JSONObject jsonObject = new JSONObject();
                jsonObject.set("userId", userId);
                result.set("logOut", jsonObject);
                //如过对方在线推送自己下线消息
                Session toSession = sessionMap.get(associationUser.getAssociatedUserId());
                this.sendMessage(JSON.toJSONString(result), toSession);
            }
        }
        sessionMap.remove(userId);
        userMap.remove(userId);
        log.info("有一连接关闭，移除userId={}的用户session, 当前在线人数为：{}",userId, sessionMap.size());
    }

    /**
     * 收到客户端消息后调用的方法
     * 后台收到客户端发送过来的消息
     * onMessage 是一个消息的中转站
     * 接受 浏览器端 socket.send 发送过来的 json数据
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("userId") String userId) {
        log.info("服务端收到用户userId={}的消息:{}", message, userId);
        JSONObject obj = JSONUtil.parseObj(message);
        String fromUserId = obj.getStr("fromId");
        String messageText = obj.getStr("messageText");
        if (obj.getInt("num")>1){
            //群聊toUserId为房间id
            List<String> toUserIds = croupChatContactsService.selectCroupByRoomId(obj.getStr("toUserId"));
            for (String toUserId:toUserIds){
                if (!toUserId.equals(userId)) {
                    CommMessage message1 = new CommMessage();
                    message1.setToUserId(toUserId);
                    message1.setRoomId(obj.getStr("toUserId"));
                    message1.setMessage(messageText);
                    message1.setFromUser(userServiceClient.querytUser(userId));
                    sendUserMessage(message1, fromUserId);
                }
            }
            log.info("收到群聊name={}消息",message);
        }else {
            CommMessage message1 = new CommMessage();
            message1.setToUserId(obj.getStr("toUserId"));
            message1.setMessage(messageText);
            message1.setFromUser(userServiceClient.querytUser(fromUserId));
            sendUserMessage(message1,fromUserId);
        }
    }

    private void sendUserMessage(CommMessage message,String fromUserId){
        Session toSession = sessionMap.get(message.getToUserId()); // 根据 to用户名来获取 session，再通过session发送消息文本
        if (toSession != null) {
            // 消息组装
            this.sendMessage(JSON.toJSONString(message), toSession);
            log.info("发送给用户userId={}，消息：{}", message.getToUserId(), JSON.toJSONString(message));
        } else {
            //用户离线，存储到数据库中
            Message message2 = new Message(UUID.randomUUID().toString(),fromUserId,message.getToUserId(),message.getMessage(), LocalDateTime.now());
            int i = messageService.saveMessage(message2);
            if (i == 1){
                log.info("存储成功");
            }else {
                log.info("存储失败");
            }
        }
    }
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("连接错误");
        error.printStackTrace();
    }

    /**
     * 服务端发送消息给客户端
     */
    public void sendMessage(String message, Session toSession) {
        try {
            log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
            toSession.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }

    /**
     * 服务端发送消息给所有客户端
     */
    private void sendAllMessage(String message) {
        try {
            for (Session session : sessionMap.values()) {
                log.info("服务端给客户端[{}]发送消息{}", session.getId(), message);
                session.getBasicRemote().sendText(message);
            }
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }

}
